#include "GUIManager.h"
#include "General Utils.hpp"

map<int, GUIPanel>					GUIManager::IDToGUIPanel;
map<int, vector<GUIPanelButton>>	GUIManager::IDToGUIPanelButton;
map<int, SDL_Rect>					GUIManager::IDToSDLRect;
map<int, Dimension>					GUIManager::IDToRelativeStartingPosition;
vector<int>							GUIManager::ActivatedPanels;
map<int, Coords>					GUIManager::IDToPanelLocation;

GUIManager* GUIManager::Instance()
{
	static GUIManager instance;
	return &instance;
}

GUIManager::GUIManager()
{
	m_panelID = 0;
}
/* ------------------------------------------------------- */
/* Control Functions ------------------------------------- */
/* ------------------------------------------------------- */
void GUIManager::ActivatePanel()
{
	IDToGUIPanel[m_panelID].FadeIn();
}

void GUIManager::DeactivePanel()
{
	IDToGUIPanel[m_panelID].FadeOut();
}

bool GUIManager::GetPanelBounds(int x, int y)
{
	vector<int>::iterator iter;
	for(iter = ActivatedPanels.begin(); iter != ActivatedPanels.end(); ++iter)
		if(IDToGUIPanel[*iter].GetPanelBounds(x, y) == true)
			return true;

	return false;
}

void GUIManager::Update()
{
	vector<int>::iterator iter;
	for(iter = ActivatedPanels.begin(); iter != ActivatedPanels.end(); ++iter)
	{
		IDToGUIPanel[*iter].Update();

		for(unsigned int a = 0; a < IDToGUIPanelButton[*iter].size(); ++a)
				IDToGUIPanelButton[*iter][a].Update();

	}
}

// Returns -1 if no button ID is in bounds
int GUIManager::GetButtonID(int mouseX, int mouseY)
{
	vector<int>::iterator iter;
	for(iter = ActivatedPanels.begin(); iter != ActivatedPanels.end(); ++iter)
	{
		if(IDToGUIPanel[*iter].GetActive()) // only check if the panel is active
		{
			for(unsigned int a = 0; a < IDToGUIPanelButton[*iter].size(); ++a)
			{
				if(IDToGUIPanelButton[*iter][a].GetBounds(mouseX, mouseY))
				{
					// Return the selected box's id
					return IDToGUIPanelButton[*iter][a].GetReferenceID();
				}	
			}
		}
	}
	return -1; // No unit should have an ID of -1
}

// Returns the ID of the button in the registered panel that the mouse is over
int GUIManager::GetActivePanelButtonID(const Vector2D& mouse)
{
	if(IDToGUIPanel[m_panelID].GetActive())
	{
		for(unsigned int a = 0; a < IDToGUIPanelButton[m_panelID].size(); ++a)
		{
			if(IDToGUIPanelButton[m_panelID][a].GetBounds(mouse.x, mouse.y))
			{
				// Return the selected box's id
				return IDToGUIPanelButton[m_panelID][a].GetReferenceID();
			}	
		}
	}
	return -1; // No unit should have an ID of -1
}

// Returns all of the button IDs on the current panel
vector<int> GUIManager::GetAllButtonID()
{
	// Create a vector that stores all of the buttons' IDs
	vector<int> unitIDs;

	// Get the buttons' IDs and store them
	for(unsigned int a = 0; a < IDToGUIPanelButton[m_panelID].size(); ++a)
		unitIDs.push_back(IDToGUIPanelButton[m_panelID][a].GetReferenceID());

	return unitIDs;

}

// Should the button's rectangle be drawn; works on current panel
void GUIManager::SetButtonShading(bool cond, int referenceID)
{
	for(unsigned int j = 0; j < IDToGUIPanelButton[m_panelID].size(); ++j)
		if(IDToGUIPanelButton[m_panelID][j].GetReferenceID() == referenceID)
			IDToGUIPanelButton[m_panelID][j].SetDrawRect(cond);
}

// Should the panel's buttons be drawn; works on current panel
void GUIManager::SetButtonShading(bool cond)
{
	for(unsigned int j = 0; j < IDToGUIPanelButton[m_panelID].size(); ++j)
		IDToGUIPanelButton[m_panelID][j].SetDrawRect(cond);
}

void GUIManager::SwapButton(bool displayNormal, int referenceID)
{
	for(unsigned int j = 0; j < IDToGUIPanelButton[m_panelID].size(); ++j)
		if(IDToGUIPanelButton[m_panelID][j].GetReferenceID() == referenceID)
			IDToGUIPanelButton[m_panelID][j].SwapImages(displayNormal);
}

void GUIManager::SwapButton(bool displayNormal)
{
	for(unsigned int j = 0; j < IDToGUIPanelButton[m_panelID].size(); ++j)
		IDToGUIPanelButton[m_panelID][j].SwapImages(displayNormal);
}

// Rebuild
// Adds a button to a panel
void GUIManager::AddButton(int referenceID, string imageID, int x, int y, int w, int h)
{
	// Create a new button
	GUIPanelButton button;
	button.SetRect(GetRect(x, y, x + w, y + w));
	button.SetReferenceID(referenceID);
	button.SetImageID(imageID);

	// Add the button
	IDToGUIPanelButton[m_panelID].push_back(button);
}

void GUIManager::AddButton(int referenceID, string normalImage, string mouseoverImage, int x, int y, int w, int h)
{
	// Create a new button
	GUIPanelButton button;
	button.SetRect(GetRect(x, y, x + w, y + w));
	button.SetReferenceID(referenceID);
	button.SetImages(normalImage.c_str(), mouseoverImage.c_str());
	button.SwapImages(true);

	// Add the button
	IDToGUIPanelButton[m_panelID].push_back(button);
}

// Adds an automatically positioned button
void GUIManager::AddButton(int referenceID, string imageID)
{
	// The coordinates and dimensions of the panel
	Coords coord = IDToGUIPanel[m_panelID].GetCoords(); // GUI panel coordinates
	Dimension dim = IDToGUIPanel[m_panelID].GetDimensions();

	// If the button location is close enough to the bottom that it will go beyond the panel
	if(IDToSDLRect[m_panelID].y + IDToSDLRect[m_panelID].h > IDToGUIPanel[m_panelID].GetBottomY())
	{
		// Reset y and push the x to the right by the image width
		IDToSDLRect[m_panelID].y = coord.y + IDToRelativeStartingPosition[m_panelID].h; // reset the button coordinates
		IDToSDLRect[m_panelID].x += IDToSDLRect[m_panelID].w; // increment the x coordinate
	}

	// If the button is past the boundries of the panel
	if(IDToSDLRect[m_panelID].x + (IDToSDLRect[m_panelID].w) > coord.x + dim.w)
	{
		return; // no more buttons allowed
	}

	
	// Our button
	GUIPanelButton button;

	button.SetRect(IDToSDLRect[m_panelID]);
	button.SetReferenceID(referenceID);
	button.SetImageID(imageID);

	IDToGUIPanelButton[m_panelID].push_back(button);

	// Increment the y location of where the next button will be placed
	IDToSDLRect[m_panelID].y += IDToSDLRect[m_panelID].h;
}

// Adds an automatically positioned button
void GUIManager::AddButton(int referenceID, string normalImage, string mouseoverImage)
{
	// The coordinates and dimensions of the panel
	Coords coord = IDToGUIPanel[m_panelID].GetCoords(); // GUI panel coordinates
	Dimension dim = IDToGUIPanel[m_panelID].GetDimensions();

	// If the button location is close enough to the bottom that it will go beyond the panel
	if(IDToSDLRect[m_panelID].y + IDToSDLRect[m_panelID].h > IDToGUIPanel[m_panelID].GetBottomY())
	{
		// Reset y and push the x to the right by the image width
		IDToSDLRect[m_panelID].y = coord.y + IDToRelativeStartingPosition[m_panelID].h; // reset the button coordinates
		IDToSDLRect[m_panelID].x += IDToSDLRect[m_panelID].w; // increment the x coordinate
	}

	// If the button is past the boundries of the panel
	if(IDToSDLRect[m_panelID].x + (IDToSDLRect[m_panelID].w) > coord.x + dim.w)
	{
		return; // no more buttons allowed
	}

	
	// Our button
	GUIPanelButton button;

	button.SetRect(IDToSDLRect[m_panelID]);
	button.SetReferenceID(referenceID);
	button.SetImages(normalImage.c_str(), mouseoverImage.c_str());
	button.SwapImages(true);

	IDToGUIPanelButton[m_panelID].push_back(button);

	// Increment the y location of where the next button will be placed
	IDToSDLRect[m_panelID].y += IDToSDLRect[m_panelID].h;
}

// Adds automatically positioned text
void GUIManager::AddText(const char* text, const OGL_Color& color, const char* font_name)
{
	// The coordinates and dimensions of the panel
	Coords coord = IDToGUIPanel[m_panelID].GetCoords(); // GUI panel coordinates
	Dimension dim = IDToGUIPanel[m_panelID].GetDimensions();
	Coords textLocation;
	textLocation.x = IDToSDLRect[m_panelID].x + 8;
	textLocation.y = IDToSDLRect[m_panelID].y - Key->GetFont(font_name)->getHeight() - 8;

	// If the button is past the boundries of the panel
	if(IDToSDLRect[m_panelID].x + (IDToSDLRect[m_panelID].w) > coord.x + dim.w)
	{
		return; // no more buttons allowed
	}
	
	IDToGUIPanel[m_panelID].AddText(textLocation.x, textLocation.y, text, color, font_name);
}

void GUIManager::ClearButtons()
{

	IDToGUIPanelButton[m_panelID].clear();
	/*Coords coord = IDToGUIPanel[m_panelID].GetCoords();
	IDToSDLRect[m_panelID].x = coord.x + IDToRelativeStartingPosition[m_panelID].w;
	IDToSDLRect[m_panelID].y = coord.y + IDToRelativeStartingPosition[m_panelID].h;*/
	IDToSDLRect[m_panelID].x = IDToPanelLocation[m_panelID].x + IDToRelativeStartingPosition[m_panelID].w;
	IDToSDLRect[m_panelID].y = IDToPanelLocation[m_panelID].y + IDToRelativeStartingPosition[m_panelID].h;
}

void GUIManager::ClearText()
{
	IDToGUIPanel[m_panelID].ClearText();
}

void GUIManager::SetRelButDist(int w, int h)
{
	IDToRelativeStartingPosition[m_panelID].w = w;
	IDToRelativeStartingPosition[m_panelID].h = h;
}
/* ------------------------------------------------------- */
/* End of Control Functions ------------------------------ */
/* ------------------------------------------------------- */



/* ------------------------------------------------------- */
/* Drawing Functions ------------------------------------- */
/* ------------------------------------------------------- */
// Renders all active GUI elements.
void GUIManager::Render() //TransOpacTransButtons
{
	// Trans
	{
		vector<int>::iterator iter;
		for(iter = ActivatedPanels.begin(); iter != ActivatedPanels.end(); ++iter)
		{
			IDToGUIPanel[*iter].DrawTrans();
		}
	}

	// Opac
	{
		vector<int>::iterator iter;
		for(iter = ActivatedPanels.begin(); iter != ActivatedPanels.end(); ++iter)
		{
			//if(IDToGUIPanel[(*iter)].GetActive())
			if(IDToGUIPanel[(*iter)].DrawExternalTextures())
			{		
				for(unsigned int a = 0; a < IDToGUIPanelButton[*iter].size(); ++a)
					IDToGUIPanelButton[*iter][a].applySurface();

				IDToGUIPanel[(*iter)].DrawOpaq();
			}
		}
	}

	// Trans Buttons
	{
		vector<int>::iterator iter;
		for(iter = ActivatedPanels.begin(); iter != ActivatedPanels.end(); ++iter)
		{
			if(IDToGUIPanel[*iter].DrawExternalTextures()) // Only draw the rect if external textures can be shown on this panel
				for(unsigned int a = 0; a < IDToGUIPanelButton[*iter].size(); ++a)
					if(IDToGUIPanelButton[*iter][a].GetDrawRect())
						IDToGUIPanelButton[*iter][a].DrawRect();

		}
	}

}
/* ------------------------------------------------------- */
/* End of Drawing Functions ------------------------------ */
/* ------------------------------------------------------- */



/* ------------------------------------------------------- */
/* Lua Handled Functions --------------------------------- */
/* ------------------------------------------------------- */
void GUIManager::CreatePanel()
{
	GUIPanel panel;
	panel.SetColor(gray);
	panel.SetActive(false);

	Coords coord;
	coord.x = 0;
	coord.y = 0;
	Dimension dim;
	dim.w = 200;
	dim.h = 200;
	panel.SetDimensions(coord, dim);
	IDToPanelLocation.insert(std::pair<int, Coords>(m_panelID, coord));
	IDToPanelLocation[m_panelID].x = coord.x;
	IDToPanelLocation[m_panelID].y = coord.y;

	panel.SetFadeIncementLevel(3.0f);
	panel.FadeOut();

	Dimension zeroDim;
	zeroDim.w = 0;
	zeroDim.h = 0;

	IDToGUIPanel.insert(std::pair<int, GUIPanel>(m_panelID, panel));
	IDToRelativeStartingPosition.insert(std::pair<int, Dimension>(m_panelID, zeroDim));
	IDToRelativeStartingPosition[m_panelID].w = zeroDim.w;
	IDToRelativeStartingPosition[m_panelID].h = zeroDim.h;

	ActivatedPanels.push_back(m_panelID);

	
}
void GUIManager::SetLocation(int x, int y, int w, int h)
{

	Coords coord;
	coord.x = x;
	coord.y = y;
	Dimension dim;
	dim.w = w;
	dim.h = h;

	IDToGUIPanel[m_panelID].SetDimensions(coord, dim);
	
	// Add the button start location & dimensions (assumes dimensions are at 32x32, but it can easily be changed)
	GameRectangle aRectangle = GetRect(x + IDToRelativeStartingPosition[m_panelID].w, IDToRelativeStartingPosition[m_panelID].h, x +32, y+32);
	SDL_Rect SDLrect = {aRectangle.x, aRectangle.y, aRectangle.width, aRectangle.height};

	IDToSDLRect.insert(std::pair<int, SDL_Rect>(m_panelID, SDLrect));

	IDToSDLRect[m_panelID].x = x;
	IDToSDLRect[m_panelID].y = y;
	IDToSDLRect[m_panelID].w = w;
	IDToSDLRect[m_panelID].h = h;

	IDToPanelLocation[m_panelID].x = x;
	IDToPanelLocation[m_panelID].y = y;
}

void GUIManager::SetColor(OGL_Color color)
{
	IDToGUIPanel[m_panelID].SetColor(color);
	IDToGUIPanel[m_panelID].SetAlpha(color.a);
}

void GUIManager::SetFadeTime(float val)
{
	IDToGUIPanel[m_panelID].SetFadeIncementLevel(val);
}
void GUIManager::SetButtonDimensions(int w, int h)
{
	IDToSDLRect[m_panelID].w = w;
	IDToSDLRect[m_panelID].h = h;
}
/* ------------------------------------------------------- */
/* End of Lua Handled Functions -------------------------- */
/* ------------------------------------------------------- */

int GUIManager::NumButtons()
{
	return IDToGUIPanelButton[m_panelID].size();
}